iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0
Mobile Development

Android Studio 30天進階學習系列 第 24

Android Studio 30天進階學習-DAY24_Compose結合XML布局(AndroidView說明&跳轉)

  • 分享至 

  • xImage
  •  

結合Compose UI和XML布局_AndroidView的說明與實作

  • 以下會做幾個最常見的操作來實作ActivityViewCompose UI之間的結合操作
    1. Compose UI 結合 XML 進行intent跳轉頁面到 一般ActivityXML

概述

View:就是我們最一開始接觸到的有JavaKotlin程式碼和XML畫面布局檔案的組成。
Compose:就是沒有XML布局檔案並且使用Kotlin語法撰寫以 @Composable 可組合式註解來組成畫面布局。

前置簡易說明實作

  1. 先建立一個layout資料夾->接著建立xml檔案(如下圖)->檔案命名->完成建立
    https://ithelp.ithome.com.tw/upload/images/20231004/201503708A7j0fA4pL.png
  2. 建立Activity檔案命名為MyActivity
    https://ithelp.ithome.com.tw/upload/images/20231004/20150370DnKXxzTV4X.png

XML布局畫面配置

  • MyActivity的XML布局配置
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyActivity">

    <Button
        android:id="@+id/previous_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Previous"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Activity_View"
        android:textAlignment="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

https://ithelp.ithome.com.tw/upload/images/20231004/20150370NKYx0rkHDy.png

  • MainActivity的XML布局配置
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/compose_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="28dp"
        android:textAlignment="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/compose_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Press me"
        android:textAlignment="center"
        android:textSize="32dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/compose_textView" />
</androidx.constraintlayout.widget.ConstraintLayout>

https://ithelp.ithome.com.tw/upload/images/20231004/20150370FhOQ2YVsNm.png

AndroidView程式碼參數說明

為什麼我們要在Compose中加入AndroidView來組合開發?
這邊我引用官方的說明如下:

您可以在 Compose UI 中加入 Android View 階層。如要使用 Compose 尚未提供的 UI 元素 (例如 AdView),這種做法就特別實用。您也可以透過這種做法重複使用自己設計的自訂檢視畫面。

參數說明:

  • factory: (Context) -> T:這是一個 lambda 函數,用於在Compose中建立一個 AndroidView。 它接受一個Context參數,通常用於從 XML 佈局檔案或程式碼建立 AndroidView。 函數會傳回一個泛型類型T,這是要嵌入到Compose中的 AndroidView 的類型。

  • modifier: Modifier = COMPILED_CODE:這是用來修飾 AndroidView 的 Compose Modifier。 Modifier是Compose中的修飾系統,用於控制佈局、樣式和行為等。 預設情況下,它被設定為COMPILED_CODE,表示沒有附加的修飾符。

  • update: (T) -> Unit = COMPILED_CODE:這是一個 lambda 函數,用於更新嵌入的 AndroidView 。 它接受一個泛型類型T的參數,即創建的 AndroidView,允許您在Compose中與該視圖進行互動。 預設情況下,它也被設定為COMPILED_CODE,表示沒有預設的更新操作。

AndroidView撰寫格式

AndroidView(
    factory={
        // 創建View參數
    },
    modifier=Modifier,
    update={
        // 更新事件
    }
)
  • 結合Compose和XML布局畫面的好處如下
    • 不熟悉或剛入門 Compose UI 編寫的開發者可以使用這個功能來快速建立一個畫面並,且可以包含 Compose 元件組合開發。
    • 以往在舊專案設計過的XML布局頁面也能搬運至此處進行再次開發。
  • 壞處大致有
    • 編寫的流程及程式碼會變長。
    • Debug時會變得更為複雜。

主程式碼撰寫

以下是使用AndroidView來結合XML布局畫面來顯示畫面。

這邊我實作的功能是在Compose結合XML的class中建立跳轉功能並跳轉到一般的ActivityXML的class上。

  • MainActivity.kt(Compose)
@Composable
fun MyView() {
    
    val inflater = LayoutInflater.from(LocalContext.current)
    val context = LocalContext.current
    
    // 定義參數來綁定View、textView、Button...等等的XML元件
    val view = remember { inflater.inflate(R.layout.compose_view, null, false) }
    val textView = remember { view.findViewById<android.widget.TextView>(R.id.compose_textView) }
    val button = remember { view.findViewById<android.widget.Button>(R.id.compose_button) }

    AndroidView(
        // 設定View為綁定的R.layout.compose_view
        factory = {view},
        update = {
            // 執行以下動作持續監聽是否有改變。
            textView.text = "Hello AndroidView"

            button.setOnClickListener {
                val intent = Intent(context, MyActivity::class.java)
                context.startActivity(intent)
            }
        }
    )
}
  • MyActivity.kt(Activity)
class MyActivity : AppCompatActivity() {
    val button by lazy { findViewById<Button>(R.id.previous_btn) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_my)

        button.setOnClickListener() {
            val intent = Intent(this, MainActivity::class.java)
            startActivity(intent)
        }
    }
}

問題Debug

若執行時發現跳轉後是直接閃退回主頁面並且在logcat中顯示如 圖1. 的問題時,需要在AndroidManifest.xml的程式碼中新增以下程式碼。

這個的問題是因為MyActivity需要使用 Theme.AppCompat 主題或其派生主題,所以需要在下列的MyActivity中添加theme的設定。

  • 圖1.
    https://ithelp.ithome.com.tw/upload/images/20231004/20150370FeCO60lsJX.png
<activity
    android:name=".MyActivity"
    android:exported="true"
    // 畫面的主題設置
    android:theme="@style/Theme.AppCompat"/>
<activity
    android:name=".MainActivity"
    android:exported="true"
    android:label="@string/app_name"
    android:theme="@style/Theme.View_Compose">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

結果截圖

  • Compose頁面結合XML布局設置
    https://ithelp.ithome.com.tw/upload/images/20231004/20150370eKOaGG6Gm9.jpg
  • Activity頁面
    https://ithelp.ithome.com.tw/upload/images/20231004/20150370XMO1Qy3T8g.jpg

上一篇
Android Studio 30天進階學習-DAY23_在JetpackCompose中使用Retrofit2抓取API資料
下一篇
Android Studio 30天進階學習-DAY25_StudioBot的簡易操作說明與心得
系列文
Android Studio 30天進階學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言